package cn.buk.tms.hotel.dao;

import cn.buk.common.util.DecimalUtil;
import cn.buk.tms.dao.AbstractDao;
import cn.buk.tms.entity.order.hotel.HotelOrder_;
import cn.buk.tms.factory.OperationLogFactory;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.entity.misc.OperationLog;
import cn.buk.tms.entity.misc.PaymentMethod;
import cn.buk.tms.entity.misc.Supplier;
import cn.buk.tms.entity.order.hotel.HotelOrder;
import cn.buk.tms.entity.order.hotel.HotelOrderPrice;
import cn.buk.tms.hotel.sc.HotelOrderSearchCriteria;
import cn.buk.common.util.DateUtil;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import jakarta.persistence.criteria.*;
import jakarta.transaction.Transactional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;

import static cn.buk.tms.common.constant.TmsOrderConstant.OPERATING_OBJECT_HOTEL_ORDER;

@Transactional
@Component
public class HotelOrderDaoImpl extends AbstractDao implements HotelOrderDao {

    private static final Logger logger = LogManager.getLogger(HotelOrderDaoImpl.class);

    /**
     * 保存酒店订单
     */
    @Override
    public int createHotelOrder(HotelOrder o) {
        em.persist(o);

        var log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(o.getEnterpriseId());
        log.setOrderId(o.getId());
        log.setOperator(o.getOperator());
        log.setContent("创建订单");

        em.persist(log);

        return o.getId();
    }

    @Override
    public HotelOrder getHotelOrderById(int id) {
        return em.find(HotelOrder.class, id);
    }

    private List<Predicate> buildPredicates_searchHotelOrders(CriteriaBuilder cb, Root<HotelOrder> root,
                                                              int enterpriseId, HotelOrderSearchCriteria sc, List<Integer> allowedCustomerIds) {
        List<Predicate> predicates = new ArrayList<>();

        Predicate predicate = cb.conjunction();
        predicates.add(predicate);

        predicate = cb.equal(root.get(HotelOrder_.enterpriseId), enterpriseId);
        predicates.add(predicate);


        if (sc.getCustomerId() == 0) {
            // 散客
            predicate = cb.equal(root.get(HotelOrder_.customerType), 0);
            predicates.add(predicate);
        } else if (sc.getCustomerId() > 0) {
            // 指定客户
            predicate = cb.equal(root.get(HotelOrder_.customer), sc.getCustomerId());
            predicates.add(predicate);
        }

        if (sc.getBeginDate() != null && sc.getEndDate() != null) {
            predicate = cb.greaterThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getBeginDate());
            predicate = cb.and(predicate, cb.lessThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getEndDate()));
            predicates.add(predicate);
        } else if (sc.getBeginDate() != null) {
            predicate = cb.greaterThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getBeginDate());
            predicates.add(predicate);
        } else if (sc.getEndDate() != null) {
            predicate = cb.lessThanOrEqualTo(root.get(HotelOrder_.createTime), sc.getEndDate());
            predicates.add(predicate);
        }

        if (sc.getName() != null && sc.getName().length() > 0) {
            // 入住人姓名
            predicate = cb.like(root.get(HotelOrder_.passengerName), "%" + sc.getName() + "%");
            predicates.add(predicate);
        }

        if (sc.getHotelName() != null && sc.getHotelName().length() > 0) {
            // 酒店名称
            predicate = cb.like(root.get(HotelOrder_.hotelName), "%" + sc.getHotelName() + "%");
            predicates.add(predicate);
        }

        if (sc.getDepartureDate() != null && sc.getDepartureDate().length() == 10) {
            // 入住日期
            try {
                predicate = cb.equal(root.get(HotelOrder_.checkInDate), DateUtil.convertToDate(sc.getDepartureDate(), "yyyy-MM-dd"));
                predicates.add(predicate);
            } catch (ParseException e) {
                logger.error(e.getMessage());
            }
        }

        //默认不查找“已取消”的订单
        if (sc.getStatus() != -1) {
            predicate = cb.equal(root.get(HotelOrder_.status), sc.getStatus());
        } else {
            predicate = cb.notEqual(root.get(HotelOrder_.status), TmsOrderConstant.HOTEL_ORDER_STATUS_CANCELED);
        }
        predicates.add(predicate);

        if (sc.getOrderNo().length() > 0) {
            predicate = cb.equal(root.get(HotelOrder_.orderNo), sc.getOrderNo());
            predicates.add(predicate);
        }

        if (sc.getOp1() != null && sc.getOp1().trim().length() > 0) {
            predicate = cb.equal(root.get(HotelOrder_.operator), sc.getOp1());
            predicates.add(predicate);
        }

        if (allowedCustomerIds != null && allowedCustomerIds.size() > 0) {
            // 只允许查看指定的企业客户的订单
            predicate = cb.in(root.get(HotelOrder_.customer).get("id")).value(allowedCustomerIds);
            predicates.add(predicate);
        }

        return predicates;
    }

    /**
     * 查找酒店订单
     */
    @Override
    public List<HotelOrder> searchHotelOrders(int enterpriseId, HotelOrderSearchCriteria sc, List<Integer> allowedCustomerIds) {
        List<HotelOrder> results = null;

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<HotelOrder> cq = cb.createQuery(HotelOrder.class);
        Root<HotelOrder> root = cq.from(HotelOrder.class);
        root.alias("o");

        var predicates0 = buildPredicates_searchHotelOrders(cb, root, enterpriseId, sc, allowedCustomerIds);


        //计算根据条件查询得出的数据总数
        CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
        Root<HotelOrder> countRoot = countQuery.from(HotelOrder.class);
        countRoot.alias("o");

        var predicates1 = buildPredicates_searchHotelOrders(cb, countRoot, enterpriseId, sc, allowedCustomerIds);

        // count items
        countQuery.select(cb.count(countRoot)).where(predicates1.toArray(new Predicate[predicates1.size()]));
        Long count = em.createQuery(countQuery).getSingleResult();

        //查询
        cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

        List<Order> orderByes = new ArrayList<>();
        orderByes.add(cb.desc(root.get("id")));

        cq.orderBy(orderByes);

        int maxResults = count.intValue();
        if (maxResults > 0) {
            sc.getPage().setRowCount(maxResults);

            results = em.createQuery(cq)
                    .setFirstResult(sc.getPage().getFirstPosition())
                    .setMaxResults(sc.getPage().getPageSize())
                    .getResultList();

//            for (FlightOrder order : results) {
//                order.getFlights().size();
//                order.getPassengers().size();
//                order.getExtras().size();
//            }
        }

        if (results == null) {
          results = new ArrayList<>();
        }

        return results;
    }

    /**
     * 修改酒店订单备注
     */
    @Override
    public int updateHotelOrderRemark(final int enterpriseId, final String username, final int orderId, final String remark) {
        HotelOrder o = em.find(HotelOrder.class, orderId);
        if (o.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("HotelOrder is not existed.");
        }

        o.setRemark(remark);
        em.merge(o);

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(o.getEnterpriseId());
        log.setOrderId(o.getId());
        log.setOperator(username);

        String content = "修改备注为: " + remark;
        log.setContent(content);
        em.persist(log);

        return 1;
    }

    /**
     * 修改酒店订单的供应商
     */
    @Override
    public int updateHotelOrderSupplier(final int enterpriseId, final String username, final int orderId, final int supplierId) {
        HotelOrder o = em.find(HotelOrder.class, orderId);
        if (o.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("HotelOrder is not existed.");
        }

        Supplier supplier = em.find(Supplier.class, supplierId);
        if (supplier.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("Supplier is not existed.");
        }

        o.setSupplier(supplier);
        em.merge(o);

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(o.getEnterpriseId());
        log.setOrderId(o.getId());
        log.setOperator(username);

        String content = "修改供应商为: " + supplier.getName();
        log.setContent(content);
        em.persist(log);

        return 1;
    }

    @Override
    public int updateHotelOrderPrice(int enterpriseId, String username, int orderId, double price, double cost, double serviceCharge, double totalAmount, double totalCost, double profit) {
        int retCode = em.createQuery("update HotelOrder o set o.price = :price, o.bottomPrice = :cost, o.serviceCharge = :serviceCharge, " +
                "o.totalAmount = :totalAmount, o.totalCost = :totalCost, o.profit = :profit, o.lastUpdate = :lastUpdate," +
                "o.priceChecked = 1 " +
                "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("price", price)
                .setParameter("cost", cost)
                .setParameter("serviceCharge", serviceCharge)
                .setParameter("totalAmount", totalAmount)
                .setParameter("totalCost", totalCost)
                .setParameter("profit", profit)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
            throw new RuntimeException("To update hotel order's price failed.");
        }
        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent("修改价格为：" + price + ", " + cost + ", " + serviceCharge + "(验价通过)。");
        em.persist(log);

        return retCode;
    }

    /**
     * 修改酒店订单的支付方式
     */
    @Override
    public int updateHotelOrderPaymentMethod(int enterpriseId, String username, int orderId, int paymentMethodId) {
        HotelOrder o = em.find(HotelOrder.class, orderId);
        if (o.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("HotelOrder is not existed.");
        }

        PaymentMethod pm = em.find(PaymentMethod.class, paymentMethodId);
        if (pm.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("PaymentMethod is not existed.");
        }

        o.setPaymentMethod(pm);
        em.merge(o);

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(o.getEnterpriseId());
        log.setOrderId(o.getId());
        log.setOperator(username);

        String content = "修改支付方式为: " + pm.getName();
        log.setContent(content);
        em.persist(log);

        return 1;
    }

  @Override
  public int submitHotelOrder(int enterpriseId, String username, int orderId) {
      int retCode = em.createQuery("update HotelOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_WAITING)
              .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode != 1) {
          throw new RuntimeException("To submit hotel order failed.");
      }

      OperationLog log = OperationLogFactory.createHotelOrderLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);

      String content = "提交酒店订单";
      log.setContent(content);
      em.persist(log);

      return retCode;
  }

    @Override
    public int approveHotelOrder(int enterpriseId, String username, int orderId, int denyCode, String denyReason) {
        int retCode = 0;
        if (denyCode == 0) {
            //审批通过
            retCode = em
                    .createQuery("update HotelOrder o set o.status = :newStatus, " +
                            "o.approvalInfo.approvalStatus = 1, " +
                            "o.lastUpdate = :lastUpdate " +
                            "where o.id = :id " +
                            "and o.enterpriseId = :enterpriseId " +
                            "and o.status = :oldStatus")
                    .setParameter("id", orderId)
                    .setParameter("enterpriseId", enterpriseId)
                    .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
                    .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_WAIT_PROCESSING)
                    .setParameter("lastUpdate", DateUtil.getCurDateTime())
                    .executeUpdate();

            if (retCode == 1) {
                OperationLog log = OperationLogFactory.createHotelOrderLog();
                log.setEnterpriseId(enterpriseId);
                log.setOrderId(orderId);
                log.setOperator(username);

                String content = "审批通过";
                if (denyReason != null) {
                    content += "(" + denyReason + ")";
                }
                log.setContent(content);
                em.persist(log);
            }
        } else {
            //审批拒绝
            retCode = em
                    .createQuery("update HotelOrder o set o.status = :newStatus, " +
                            "o.approvalInfo.approvalStatus = 0, " +
                            "o.approvalInfo.approvalDenyCode = :denyCode, " +
                            "o.approvalInfo.approvalDenyReason = :denyReason, " +
                            "o.lastUpdate = :lastUpdate " +
                            "where o.id = :id " +
                            "and o.enterpriseId = :enterpriseId " +
                            "and o.status = :oldStatus")
                    .setParameter("id", orderId)
                    .setParameter("enterpriseId", enterpriseId)
                    .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
                    .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_CANCELED)
                    .setParameter("denyCode", denyCode + "")
                    .setParameter("denyReason", denyReason)
                    .setParameter("lastUpdate", DateUtil.getCurDateTime())
                    .executeUpdate();

            if (retCode == 1) {
                OperationLog log = OperationLogFactory.createHotelOrderLog();
                log.setEnterpriseId(enterpriseId);
                log.setOrderId(orderId);
                log.setOperator(username);

                String content = "审批拒绝(" + denyReason + ")，订单取消";
                log.setContent(content);
                em.persist(log);

            }
        }

        return retCode;
    }

    @Override
    public int processHotelOrder(int enterpriseId, String username, int orderId) {
        int retCode = em.createQuery("update HotelOrder o set o.status = :newStatus, o.ticketer = :ticketer, o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("oldStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_WAIT_PROCESSING)
                .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_PROCESSING)
                .setParameter("ticketer", username)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
          throw new RuntimeException("update status failed.");
        }

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);

        String content = "处理订单";
        log.setContent(content);
        em.persist(log);

        return 1;
    }

    @Override
    public int finishHotelOrder(int enterpriseId, String username, int orderId, String confirmNo) {
        HotelOrder hotelOrder = em.find(HotelOrder.class, orderId);
        if (hotelOrder == null || hotelOrder.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("Hotel order is not existed.");
        }

        em.refresh(hotelOrder);

        if (hotelOrder.getStatus() != TmsOrderConstant.HOTEL_ORDER_STATUS_PROCESSING) {
            throw new RuntimeException("Hotel order is not ready for finishing.");
        }

        hotelOrder.setStatus(TmsOrderConstant.HOTEL_ORDER_STATUS_DONE);
        hotelOrder.setLastUpdate(DateUtil.getCurDateTime());
        if (hotelOrder.getReservationChannel() != null && hotelOrder.getReservationChannel() == 0) {
            //人工预订渠道
            hotelOrder.setSupplierConfirmNo(confirmNo);
        }

        em.merge(hotelOrder);

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);

        String content = "订单处理完毕(" + confirmNo + ")";
        log.setContent(content);
        em.persist(log);

        return 1;
    }

    @Override
    public void appendHotelOrderHistory(int enterpriseId, String username, int orderId, String remark) {
        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent(remark);

        em.persist(log);

    }

    @Override
    public List<OperationLog> searchHotelOrderHistory(int enterpriseId, int orderId) {
        return searchOrderHistory(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER, orderId);
    }

    /**
     * 取消酒店订单
     */
    @Override
    public int cancelHotelOrder(int enterpriseId, String username, int hotelOrderId, String remark) {
        int retCode = em.createQuery("update HotelOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                "where o.id = :id " +
                "and o.enterpriseId = :enterpriseId " +
                "and o.status in (:oldStatus1, :oldStatus2, :oldStatus3, :oldStatus4)")
                .setParameter("id", hotelOrderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("oldStatus1", TmsOrderConstant.HOTEL_ORDER_STATUS_WAITING)
                .setParameter("oldStatus2", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
                .setParameter("oldStatus3", TmsOrderConstant.HOTEL_ORDER_STATUS_WAIT_PROCESSING)
                .setParameter("oldStatus4", TmsOrderConstant.HOTEL_ORDER_STATUS_PROCESSING)
                .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_CANCELED)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
          throw new RuntimeException("To cancel hotel order failed.");
        }

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOperator(username);
        log.setOrderId(hotelOrderId);
        log.setContent("取消订单： " + remark);
        em.persist(log);

        return retCode;
    }

    /**
     * 回滚酒店订单
     */
    @Override
    public int rollbackHotelOrder(int enterpriseId, String username, int orderId, final String remark) {
        int retCode = em.createQuery("update HotelOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId and o.status in (:oldStatus1)")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("oldStatus1", TmsOrderConstant.HOTEL_ORDER_STATUS_DONE)
                .setParameter("newStatus", TmsOrderConstant.HOTEL_ORDER_STATUS_PROCESSING)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
          throw new RuntimeException("To rollback hotel order failed.");
        }

        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOperator(username);
        log.setOrderId(orderId);
        log.setContent("订单回滚: " + remark);
        em.persist(log);

        return retCode;
    }

  @Override
  public int updateHotelOrderSupplierOrderStatus(int enterpriseId, String username, final int orderId,
                                                 String supplierOrderId,
                                                 int supplierOrderStatus,
                                                 int orderConfirmType,
                                                 String orderConfirmNo,
                                                 int orderRejectType,
                                                 String orderRejectReason,
                                                 String supplierRemark) {
      int retCode = em.createQuery("update HotelOrder o set o.supplierOrderNo = :supplierOrderNo, " +
              "o.supplierOrderStatus = :supplierOrderStatus, " +
              "o.supplierConfirmType = :orderConfirmType, " +
              "o.supplierConfirmNo = :orderConfirmNo, " +
              "o.supplierRejectType = :orderRejectType, " +
              "o.supplierRejectReason = :orderRejectReason, " +
              "o.supplierRemark = :supplierRemark, " +
              "o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("supplierOrderNo", supplierOrderId)
              .setParameter("supplierOrderStatus", supplierOrderStatus)
              .setParameter("orderConfirmType", orderConfirmType)
              .setParameter("orderConfirmNo", orderConfirmNo)
              .setParameter("orderRejectType", orderRejectType)
              .setParameter("orderRejectReason", orderRejectReason)
              .setParameter("supplierRemark", supplierRemark)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode != 1) {
          throw new RuntimeException("To updateHotelOrderSupplierOrderStatus failed.");
      }

      OperationLog log = OperationLogFactory.createHotelOrderLog();
      log.setEnterpriseId(enterpriseId);
      log.setOperator(username);
      log.setOrderId(orderId);
      log.setContent("供应商订单状态变化为: " + HotelOrder.getSupplierOrderStatusDesc(supplierOrderStatus));
      em.persist(log);

      return retCode;
  }

  @Override
  public List<HotelOrder> searchNeedAssignApproverHotelOrders(int enterpriseId) {
      final Date startDate = DateUtil.getYesterday();
      return em.createQuery("select o from HotelOrder o "
              + "where o.enterpriseId = :enterpriseId " +
              "and o.status = :status " +
              "and o.approvalInfo.specifiedApprover is null " +
              "and o.createTime >= :createDate "
              + "order by o.id", HotelOrder.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
              .setParameter("createDate", startDate)
              .getResultList();
  }

  @Override
  public int updateHotelOrderApprover(int enterpriseId, String username, int orderId, String approver) {
      int retCode = em.createQuery("update HotelOrder o set o.approvalInfo.specifiedApprover = :approver," +
              "o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("approver", approver)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode > 0) {
          OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
          log.setOperator(username);
          log.setOrderId(orderId);
          log.setContent("分派审批人为 " + approver);
          em.persist(log);
      }
      return retCode;
  }

  @Override
  public List<HotelOrder> searchNeedPriceCheckHotelOrders(int enterpriseId, Date startDate) {
      return em.createQuery("select o from HotelOrder o "
              + "where o.enterpriseId = :enterpriseId and (o.status = :status1 or o.status = :status2) and o.createTime >= :createDate "
              + "order by o.id desc", HotelOrder.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status1", TmsOrderConstant.HOTEL_ORDER_STATUS_WAITING)
              .setParameter("status2", TmsOrderConstant.HOTEL_ORDER_STATUS_SUBMITTED)
              .setParameter("createDate", startDate)
              .getResultList();
  }

  @Override
  public void updateHotelOrderPriceChecked(int enterpriseId, int orderId, String username, Integer checkStatus, String remark) {
      if (checkStatus != null) {
          int retCode = em.createQuery("update HotelOrder o set o.priceChecked = :checkStatus," +
                  "o.lastUpdate = :lastUpdate, " +
                  "o.priceCheckedTime = :checkTime " +
                  "where o.id = :id")
                  .setParameter("id", orderId)
                  .setParameter("checkStatus", checkStatus)
                  .setParameter("checkTime", DateUtil.getCurDateTime())
                  .setParameter("lastUpdate", DateUtil.getCurDateTime())
                  .executeUpdate();
          if (retCode != 1) {
              throw new RuntimeException("It is failed to update hotel order price check status.");
          }
      }
      OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
      log.setOperator(username);
      log.setOrderId(orderId);
      log.setContent(remark);
      em.persist(log);

  }

    @Override
    public void updateHotelOrderPrice(final int enterpriseId, final String username, final int orderId,
                                      final Set<HotelOrderPrice> newPrices) {
        HotelOrder o = em.find(HotelOrder.class, orderId);

        final int roomCount = o.getRoomCount();
        //入住天数，和价格详情数一样
        final int nightCount = o.getPrices().size();

        double totalCost = 0;
        for(HotelOrderPrice newPrice: newPrices) {
            totalCost += newPrice.getSupplierInclusiveAmount() * roomCount;
            for(HotelOrderPrice oldPrice: o.getPrices()) {
                if (oldPrice.getId() == newPrice.getId()) {
                    oldPrice.setSupplierInclusiveAmount(newPrice.getSupplierInclusiveAmount());
                    oldPrice.setLastUpdate(DateUtil.getCurDateTime());
                }
            }
        }
        double cost = totalCost / (roomCount * nightCount);

        //保留两位数
        totalCost = DecimalUtil.keepScale2(totalCost);
        cost = DecimalUtil.keepScale2(cost);

        o.setBottomPrice(cost);
        o.setTotalCost(totalCost);

        double profit = o.getTotalAmount() - totalCost;
        profit = DecimalUtil.keepScale2(profit);

        o.setProfit(profit);
        o.setLastUpdate(DateUtil.getCurDateTime());

        em.merge(o);


        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOperator(username);
        log.setOrderId(orderId);
        log.setContent("修改酒店订单成本：每晚均价为" + cost + ", 总成本为" + totalCost + ", 利润为" + profit);
        em.persist(log);

    }

  @Override
  public List<HotelOrder> searchMeetPolicyHotelOrders(int enterpriseId) {
      final Date startDate = DateUtil.getYesterday();
      return em.createQuery("select o from HotelOrder o "
              + "where o.enterpriseId = :enterpriseId " +
              "and o.approvalInfo.violationStatus is null " +
              "and o.createTime >= :createDate "
              + "order by o.id", HotelOrder.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("createDate", startDate)
              .getResultList();
  }

    @Override
    public void updateHotelOrderViolationStatus(int enterpriseId, String username, int orderId, int status, String remark) {
        int retCode = em.createQuery("update HotelOrder o set " +
                "o.approvalInfo.violationStatus = :status, " +
                "o.approvalInfo.violationReason = :reason, " +
                "o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("status", status)
                .setParameter("reason", remark)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode > 0) {
            OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
            log.setOperator(username);
            log.setOrderId(orderId);
            String content = status == 0 ? "未违反差旅政策": "违反了差旅政策";
            content += "(" + remark + ")";
            log.setContent(content);
            em.persist(log);
        }
    }

  @Override
  public List<HotelOrder> checkHotelOrderCityIdIsNull(int enterpriseId) {
      final Date startDate = DateUtil.getYesterday();
      return em.createQuery("select o from HotelOrder o "
              + "where o.enterpriseId = :enterpriseId " +
              "and (o.cityId is null or o.hotelAddress is null) " +
              "and o.createTime >= :createDate "
              + "order by o.id", HotelOrder.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("createDate", startDate)
              .getResultList();
  }

  @Override
  public void updateHotelOrderCityInfo(int enterpriseId, String username, int orderId, int cityId, String cityName) {
      int retCode = em.createQuery("update HotelOrder o set " +
              "o.cityId = :cityId, " +
              "o.cityName = :cityName, " +
              "o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("cityId", cityId)
              .setParameter("cityName", cityName)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode > 0) {
          OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
          log.setOperator(username);
          log.setOrderId(orderId);
          String content = "修改城市ID为(" + cityId + "), 城市名为(" + cityName + ")." ;
          log.setContent(content);
          em.persist(log);
      }
  }

  @Override
  public int updateHotelOrderChannel(int enterpriseId, String username, int orderId, int channel) {
      int retCode = em.createQuery("update HotelOrder o set " +
              "o.reservationChannel = :channel, " +
              "o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("channel", channel)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode > 0) {
          OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
          log.setOperator(username);
          log.setOrderId(orderId);
          String content = "修改预订渠道为(" + channel + ")." ;
          log.setContent(content);
          em.persist(log);
      }
      return retCode;
  }

  @Override
  public List<HotelOrder> searchHotelOrderByStatus(int enterpriseId, int status, int max) {
    return em.createQuery("select o from HotelOrder o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.status = :status " +
            "order by o.id desc", HotelOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("status", status)
            .setMaxResults(max)
            .getResultList();
  }

  @Override
  public void updateHotelOrderHotelAddress(int enterpriseId, String username, int orderId, String address) {
      int retCode = em.createQuery("update HotelOrder o set " +
              "o.hotelAddress = :address, " +
              "o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("address", address)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode > 0) {
          OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
          log.setOperator(username);
          log.setOrderId(orderId);
          String content = "修改酒店地址" ;
          log.setContent(content);
          em.persist(log);
      }
  }

    @Override
    public void updateHotelOrderNotifyStatus(int enterpriseId, String username, int orderId, String remark) {
        int retCode = em.createQuery("update HotelOrder o set " +
                "o.notifyStatus = 1, " +
                "o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode > 0) {
            OperationLog log = OperationLog.createLog(enterpriseId, OPERATING_OBJECT_HOTEL_ORDER);
            log.setOperator(username);
            log.setOrderId(orderId);
            String content = "发送通知：" + remark;
            log.setContent(content);
            em.persist(log);
        }
    }

  @Override
  public List<HotelOrder> searchUnpaidOrders(int max) {
      return em.createQuery("select o from HotelOrder o " +
              "where (o.payStatus is null or o.payStatus <> 2) " +
              "and o.status = :status " +
              "and o.createTime >= :createTime " +
              "order by o.id", HotelOrder.class)
              .setParameter("status", TmsOrderConstant.HOTEL_ORDER_STATUS_DONE)
              .setParameter("createTime", getMinBeginDate())
              .setMaxResults(max)
              .getResultList();
  }

    @Override
    public int setOrderWriteOff(int enterpriseId, String username, int orderId, String remark) {
        int retCode = em.createQuery("update HotelOrder o set " +
                "o.payStatus = 2 " +
                "where o.id = :id and o.enterpriseId = :enterpriseId and (o.payStatus is null or o.payStatus <> 2)")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = createHotelOrderLog(enterpriseId, orderId, username, "已销账：" + remark);
            em.persist(log);
        }

        return retCode;
    }

    private OperationLog createHotelOrderLog(int enterpriseId, int orderId, String username, String s) {
        OperationLog log = OperationLogFactory.createHotelOrderLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent(s);

        return log;
    }
}
